from __future__ import annotations
import asyncio
import inspect
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union, get_type_hints, TYPE_CHECKING, AsyncGenerator

from axiom_boot.conf.manager import Settings
from axiom_boot.core.exceptions import CircularDependencyError, ServiceNotFoundException, FrameworkException
from axiom_boot.di.dependency import Autowired, ServiceDefinition
from axiom_boot.di.component_scanner import ComponentScanner
from axiom_boot.di.definition_reader import DefinitionReader
from axiom_boot.di.interfaces import ApplicationProcessor
from axiom_boot.logging.setup import get_logger

if TYPE_CHECKING:
    # 此处仅为类型提示，不会造成循环依赖。
    from axiom_boot.di.application import AxiomApplication

T = TypeVar('T')
logger = get_logger(__name__)


class ApplicationContext:
    """
    应用上下文，整个DI系统的核心。

    它负责管理应用的整个生命周期：
    1. 扫描组件 (Component Scanning)
    2. 读取服务定义 (Definition Reading)
    3. 实例化服务 (Instantiation)
    4. 依赖注入 (Dependency Injection)
    5. 生命周期管理 (Lifecycle Management)
    """
    
    def __init__(
        self,
        scan_base_packages: Optional[List[str]] = None,
        config_file: Optional[str] = None,
        mode: str = 'web'
    ):
        self.mode = mode
        self._settings: Settings = Settings(_env_file=config_file)
        self._settings.run_mode = mode
        
        self._definitions: Dict[str, ServiceDefinition] = {}
        self._instances: Dict[str, Any] = {}
        self._resolution_stack: List[str] = []
        self._is_refreshed = False
        # 为每个服务创建一个锁，以确保在并发环境下的创建安全
        self._creation_locks: Dict[str, asyncio.Lock] = {}
        # 保存需要生命周期管理的异步生成器
        self._managed_generators: List[AsyncGenerator] = []
        self._scan_base_packages = scan_base_packages or self._settings.scan_base_dirs
        self._app: Optional["AxiomApplication"] = None

    def refresh_blocking(self):
        """同步版本的 refresh，用于在非 asyncio 环境下（如脚本、Celery worker）初始化上下文。"""
        logger.debug("正在以阻塞方式刷新应用上下文...")
        try:
            loop = asyncio.get_running_loop()
            if loop.is_running():
                logger.warning("在已运行的事件循环中调用了 refresh_blocking。这可能导致意外行为。")
                future = asyncio.run_coroutine_threadsafe(self.refresh(), loop)
                future.result()
        except RuntimeError:  # 没有正在运行的事件循环
            asyncio.run(self.refresh())
    
    def get_blocking(self, identifier: Union[Type[T], str]) -> T:
        """同步版本的 get，用于在非 asyncio 环境下获取服务实例。"""
        logger.debug(f"正在以阻塞方式获取服务: {identifier}")
        try:
            loop = asyncio.get_running_loop()
            if loop.is_running():
                logger.warning("在已运行的事件循环中调用了 get_blocking。")
                future = asyncio.run_coroutine_threadsafe(self.get(identifier), loop)
                return future.result()
        except RuntimeError:  # No running event loop
            return asyncio.run(self.get(identifier))

    def register_instance(self, instance: Any, name: str, provides: Optional[Type] = None):
        """
        手动将一个已存在的对象实例注册到 DI 容器中。
        这对于集成第三方库或在处理器中动态创建对象很有用。
        """
        service_name = name.lower()

        if service_name in self._instances:
            logger.warning(f"正在覆盖已存在的实例: '{service_name}'")
        
        self._instances[service_name] = instance
        
        if service_name not in self._definitions:
            definition = ServiceDefinition(
                name=service_name,
                target=lambda: instance,
                provides=provides or instance.__class__
            )
            self._definitions[service_name] = definition

        logger.info(f"已将实例 '{service_name}' (类型: {instance.__class__.__name__}) 手动注册到 DI 容器。")

    def set_app(self, app: "AxiomApplication"):
        """将主应用实例注入上下文，以便处理器可以访问它。"""
        self._app = app

    def has_definition_for(self, identifier: Any) -> bool:
        """
        安全地检查是否存在给定标识符的服务定义，而不会引发异常。
        用于在尝试注入前，判断一个类型是否为可注入的服务。

        Args:
            identifier: 类型、别名或服务名称。

        Returns:
            如果存在服务定义，则为 True，否则为 False。
        """
        try:
            # 复用内部的名称解析逻辑。如果未找到，它会抛出 ServiceNotFoundException。
            self._resolve_service_name(identifier)
            return True
        except ServiceNotFoundException:
            return False

    async def refresh(self):
        """
        刷新应用上下文。
        这是启动DI容器的入口点，它会按顺序执行所有初始化步骤。
        """
        if self._is_refreshed:
            logger.warning("应用上下文已被刷新，请勿重复调用 refresh()。")
            return

        logger.info("正在刷新应用上下文...")

        # 阶段 1: 扫描和读取定义
        logger.debug("阶段 1: 扫描和读取服务定义...")
        self._register_core_beans()
        scanner = ComponentScanner(self._scan_base_packages)
        modules = scanner.scan()
        reader = DefinitionReader()
        self._definitions.update(reader.read(modules, self._settings))
        logger.debug(f"定义读取完成，共找到 {len(self._definitions)} 个服务定义。")

        # 阶段 2: 创建并执行生命周期处理器
        logger.debug("阶段 2: 创建并执行生命周期处理器...")
        await self._initialize_processors()

        # 阶段 3: 实例化所有剩余的单例服务
        logger.debug("阶段 3: 实例化所有剩余的单例服务...")
        await self._instantiate_singletons()

        self._is_refreshed = True
        logger.info("应用上下文刷新完成。")

    def _register_core_beans(self):
        """手动注册框架自身提供的核心服务定义。"""
        # 将配置实例注册为一个服务
        settings_def = ServiceDefinition(
            name="settings",
            target=lambda: self._settings,
            provides=self._settings.__class__
        )
        self._definitions[settings_def.name] = settings_def

        # 注入 ApplicationContext 自身
        context_def = ServiceDefinition(
            name="applicationcontext",
            target=lambda: self,
            provides=ApplicationContext
        )
        self._definitions[context_def.name] = context_def

    async def _initialize_processors(self):
        """
        发现、排序并执行所有的 ApplicationProcessor。
        这是确保基础设施在业务服务之前准备就绪的关键步骤。
        """
        processor_definitions = []
        for name, definition in self._definitions.items():
            target_class = definition.target
            if inspect.isclass(target_class) and issubclass(target_class, ApplicationProcessor) and not inspect.isabstract(target_class):
                processor_definitions.append(definition)

        # 实例化处理器
        processors: List[ApplicationProcessor] = []
        for definition in processor_definitions:
            processor_instance = await self.get(definition.name)
            processors.append(processor_instance)

        # 根据 @order 装饰器排序
        processors.sort(key=lambda p: getattr(p, '_axiom_order', float('inf')))

        logger.info(f"【应用上下文】: 将按以下顺序执行 {len(processors)} 个应用处理器: {[p.__class__.__name__ for p in processors]}")

        # 依次执行处理器
        for processor in processors:
            logger.info(f"【应用上下文】: ==> 准备执行处理器: {processor.__class__.__name__}")
            if not self._app:
                raise FrameworkException("AxiomApplication 实例未设置到 ApplicationContext 中。")
            await processor.process(self._app)
            logger.info(f"【应用上下文】: <== 处理器: {processor.__class__.__name__} 执行完毕。")

    async def _instantiate_singletons(self):
        """
        遍历所有服务定义，并按需创建*非处理器*的单例实例。
        """
        logger.debug(f"即将从 {len(self._definitions)} 个定义中实例化单例服务...")
        for name, definition in self._definitions.items():
            # 确保不会重新处理已经被实例化的处理器
            target_class = definition.target
            is_processor = inspect.isclass(target_class) and issubclass(target_class, ApplicationProcessor) and not inspect.isabstract(target_class)

            if not is_processor:
                # get() 方法会处理按需创建和缓存
                await self.get(name)

        logger.debug("所有单例服务均已创建或准备就绪。")

    async def get(self, identifier: Union[Type[T], str]) -> T:
        """
        从容器中异步获取一个服务实例。

        此方法是并发安全的。如果多个协程同时请求一个尚未创建的服务，
        只有一个协程会执行创建过程，其他协程会等待并获取最终创建的实例。
        """
        service_name = self._resolve_service_name(identifier)
        
        # 优化：如果实例已存在，直接返回，避免不必要的锁操作
        if service_name in self._instances:
            return self._instances[service_name]
            
        # 获取或创建该服务的锁
        lock = self._creation_locks.get(service_name)
        if lock is None:
            lock = asyncio.Lock()
            self._creation_locks[service_name] = lock

        async with lock:
            # 关键：在获取锁之后，再次检查实例是否存在。
            # 因为在等待锁的过程中，可能已有其他协程完成了实例的创建。
            if service_name in self._instances:
                return self._instances[service_name]

            logger.debug(f"请求获取服务 '{service_name}' (由标识符 '{getattr(identifier, '__name__', identifier)}' 解析而来).")

            if service_name in self._resolution_stack:
                raise CircularDependencyError(self._resolution_stack + [service_name])

            self._resolution_stack.append(service_name)

            try:
                instance = await self._create_instance(service_name)
                self._instances[service_name] = instance
                logger.debug(f"已成功创建并缓存 '{service_name}' 的实例。")
                return instance
            finally:
                self._resolution_stack.pop()

    async def get_optional(self, identifier: Union[Type[T], str]) -> Optional[T]:
        """
        从容器中异步获取一个可选的服务实例。

        如果服务定义不存在，此方法将返回 None 而不是引发 ServiceNotFoundException。
        """
        try:
            return await self.get(identifier)
        except ServiceNotFoundException:
            logger.debug(f"可选服务 '{getattr(identifier, '__name__', identifier)}' 未在容器中找到，将返回 None。")
            return None

    async def close(self):
        """
        优雅地关闭应用上下文，释放所有管理的资源。
        特别是，它会正确地关闭所有通过异步生成器创建的服务。
        """
        logger.info("正在关闭应用上下文并释放资源...")
        for gen in self._managed_generators:
            try:
                # 使用 aclose() 来正确地关闭异步生成器并触发其 finally 块
                await gen.aclose()
            except Exception as e:
                logger.error(f"关闭服务资源 '{getattr(gen, '__name__', 'unknown')}' 时发生错误: {e}", exc_info=True)

        self._instances.clear()
        self._definitions.clear()
        self._managed_generators.clear()
        logger.info("应用上下文已成功关闭。")

    def get_instances_by_superclass(self, superclass: Type[T]) -> List[T]:
        """获取所有已实例化的、作为指定超类子类的服务实例。"""
        matches = []
        for instance in self._instances.values():
            if isinstance(instance, superclass):
                matches.append(instance)
        return matches

    def get_controllers(self) -> List[Any]:
        """获取所有被标记为控制器的服务实例。"""
        controllers = []
        for definition in self._definitions.values():
            target = definition.target
            if inspect.isclass(target) and hasattr(target, '_axiom_is_controller'):
                # We can safely assume the instance exists because singletons are pre-instantiated
                instance = self._instances.get(definition.name)
                if instance:
                    controllers.append(instance)
        return controllers

    async def _create_instance(self, service_name: str) -> Any:
        """根据服务定义创建并注入服务实例。"""
        logger.debug(f"正在为服务 '{service_name}' 创建实例...")
        if service_name not in self._definitions:
            raise ServiceNotFoundException(f"未找到服务 '{service_name}'。")

        definition = self._definitions[service_name]
        target = definition.target
        instance: Any

        if inspect.isclass(target):
            # --- 1. 构造函数注入 ---
            init_kwargs = await self._resolve_dependencies_for_callable(target.__init__)
            instance = target(**init_kwargs)
            # --- 2. 字段注入 ---
            await self._perform_field_injection(instance)
        else:  # 这是一个工厂函数
            factory_kwargs = await self._resolve_dependencies_for_callable(target)
            
            if inspect.isasyncgenfunction(target):
                # --- 3. 异步生成器工厂 ---
                logger.debug(f"正在通过异步生成器工厂 '{target.__name__}' 创建服务 '{service_name}'...")
                generator = target(**factory_kwargs)
                # 持有对生成器的引用，以防止其被过早地垃圾回收
                self._managed_generators.append(generator)
                instance = await generator.__anext__()  # 获取 yield 的值
            elif inspect.iscoroutinefunction(target):
                # --- 4. 异步工厂 ---
                logger.debug(f"正在通过异步工厂 '{target.__name__}' 创建服务 '{service_name}'...")
                instance = await target(**factory_kwargs)
            else:
                # --- 5. 普通工厂 ---
                logger.debug(f"正在通过普通工厂 '{target.__name__}' 创建服务 '{service_name}'...")
                instance = target(**factory_kwargs)

        return instance

    async def _resolve_dependencies_for_callable(self, target_callable: Callable) -> Dict[str, Any]:
        """一个辅助方法，用于解析任何可调用对象（函数或方法）的依赖。"""
        logger.debug(f"--> [DIAGNOSTIC] 开始为可调用对象 '{target_callable.__qualname__}' 解析依赖...")
        try:
            type_hints = get_type_hints(target_callable)
            logger.debug(f"--> [DIAGNOSTIC] 为 '{target_callable.__qualname__}' 解析出的原始类型提示: {type_hints}")
        except Exception as e:
            logger.error(f"--> [DIAGNOSTIC] 为 '{target_callable.__qualname__}' 解析类型提示时发生意外错误: {e}", exc_info=True)
            type_hints = {}

        sig = inspect.signature(target_callable)
        kwargs = {}
        for param in sig.parameters.values():
            if param.name == 'self':
                continue
            if param.default is not inspect.Parameter.empty and not isinstance(param.default, Autowired):
                continue

            dependency_id = type_hints.get(param.name)
            if isinstance(param.default, Autowired) and param.default.dependency:
                dependency_id = param.default.dependency
            
            # 新增的、用于精确定位错误来源的诊断日志
            logger.debug(
                f"--> [DIAGNOSTIC] In callable '{target_callable.__qualname__}', resolving param '{param.name}'... "
                f"Resolved dependency_id: '{dependency_id}' (Type: {type(dependency_id)})"
            )

            if not dependency_id:
                raise FrameworkException(f"无法为 '{target_callable.__name__}' 的参数 '{param.name}' 注入依赖：无法解析其类型注解。")
            
            kwargs[param.name] = await self.get(dependency_id)
        return kwargs

    async def _perform_field_injection(self, instance: Any):
        """对实例的字段执行 @autowired 注入。"""
        # 遍历实例的类继承链(MRO)，以处理父类中定义的注入字段
        for cls in inspect.getmro(instance.__class__):
            # 检查当前类的 __dict__，避免处理父类已处理过的属性
            for attr_name, marker in cls.__dict__.items():
                if not isinstance(marker, Autowired):
                    continue

                # 确认注入目标是实例上的原始 Autowired marker，避免重复注入
                if getattr(instance, attr_name) is not marker:
                    continue

                logger.debug(f"-> 在类 '{cls.__name__}' 上为实例 '{instance.__class__.__name__}' 注入字段 '{attr_name}'。")
                
                dependency_id = marker.dependency
                if dependency_id is None:
                    # 如果未指定依赖项，则尝试从类型提示中推断
                    try:
                        # 必须从定义属性的类(cls)中获取类型提示
                        type_hints = get_type_hints(cls)
                        dependency_id = type_hints.get(attr_name)
                    except (TypeError, NameError) as e:
                        logger.warning(f"无法为字段 '{attr_name}' 解析类型提示: {e}")
                        dependency_id = None
                
                if not dependency_id:
                    raise FrameworkException(
                        f"无法为 '{instance.__class__.__name__}' 的字段 '{attr_name}' 注入依赖: "
                        f"无法解析其类型注解或未在 autowired() 中指定。"
                    )
                
                logger.debug(f"--> 字段 '{attr_name}' 的依赖被识别为: {getattr(dependency_id, '__name__', dependency_id)}")
                dependency_instance = await self.get(dependency_id)
                
                # 在实例上设置属性，这将遮蔽(shadow)类同名属性
                setattr(instance, attr_name, dependency_instance)
    
    def _resolve_service_name(self, identifier: Union[Type[T], str]) -> str:
        """
        根据标识符（类型或名称）解析出标准化的服务名称。
        增加了对 @Primary 装饰器的支持。
        """
        if isinstance(identifier, str):
            # 如果是字符串，直接认为是服务名
            return identifier.lower()

        if not inspect.isclass(identifier) and not inspect.isabstract(identifier):
            # 增强的诊断日志
            service_def_info = "N/A"
            temp_identifier_name = str(identifier) # Use a temp name for logging
            
            # 尝试获取服务定义信息
            service_name_for_lookup = ""
            try:
                # 尝试将标识符转换为服务名称字符串
                # 这是一个启发式方法，因为此时我们知道它不是一个类
                if hasattr(identifier, '__name__'):
                    service_name_for_lookup = identifier.__name__.lower()
                elif isinstance(identifier, str):
                    service_name_for_lookup = identifier.lower()

                if service_name_for_lookup and service_name_for_lookup in self._definitions:
                    service_def_info = str(self._definitions[service_name_for_lookup])
            except Exception:
                # 忽略在日志记录期间可能出现的任何错误
                pass

            logger.error(
                f"\n!!!!!!!!!!!!!!!!!!!!!! FATAL DI ERROR !!!!!!!!!!!!!!!!!!!!!!\n"
                f"  - Problem: Attempting to inject a non-class object.\n"
                f"  - Offending Identifier: {temp_identifier_name}\n"
                f"  - Identifier Type: {type(identifier)}\n"
                f"  - Associated Service Definition: {service_def_info}\n"
                f"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
            )
            raise TypeError(f"按类型注入时，标识符必须是类或抽象基类，但收到了：{type(identifier)}")

        # 按类型查找
        implementations = []
        for name, definition in self._definitions.items():
            provided_type = definition.provides or (definition.target if inspect.isclass(definition.target) else None)
            if provided_type and issubclass(provided_type, identifier):
                implementations.append(definition)
        
        if not implementations:
            raise ServiceNotFoundException(
                f"未找到类型为 '{identifier.__name__}' 的服务定义。"
            )

        if len(implementations) == 1:
            return implementations[0].name

        # 歧义解决：当有多个实现时，寻找 @Primary
        primary_implementations = [
            impl for impl in implementations if getattr(impl.target, '_axiom_is_primary', False)
        ]

        if len(primary_implementations) == 1:
            return primary_implementations[0].name

        if len(primary_implementations) > 1:
            primary_names = [impl.name for impl in primary_implementations]
            raise FrameworkException(
                f"为抽象基类 '{identifier.__name__}' 找到多个被 @primary 标记的具体实现: {primary_names}。"
                "请确保只有一个主实现。"
            )
        
        # 存在多个实现，但没有一个被标记为 @Primary
        impl_names = [impl.name for impl in implementations]
        raise FrameworkException(
            f"为抽象基类 '{identifier.__name__}' 找到多个具体实现: {impl_names}。"
            "请使用 @primary 标记首选实现，或通过名称明确指定要注入的服务。"
        )

    async def _close_services(self) -> None:
        """关闭所有可关闭的服务。"""
        # ... existing code ...